/*
 * @Description:mongo数据库接口
 * @Author: maskMan
 * @LastEditTime: 2025-03-03 10:26:08
 */
import { monConf } from "../public/config";
import { NDefine } from "../types/define";
import mongoose from "mongoose";
import { Istruct, SchemaList, Table, TCondition, structList, ISort, BulkOperations } from "./struct";
const mongooseSequence = require("mongoose-sequence")(mongoose); // 引入自增插件
const Schema = mongoose.Schema;
export default class Mondb {
  /**架构列表 */
  private static _schemaList: SchemaList<InstanceType<typeof Schema>> = {};
  /**
   * @description:mongo连接 返回成功/失败
   * @return {*  Promise<布尔型>}
   */
  public static connect(): Promise<boolean> {
    return new Promise(resolve => {
      const url = `mongodb://${monConf.user}:${monConf.password}@127.0.0.1:27017/${monConf.dbName}?authSource=admin`;
      mongoose
        .connect(url)
        .then(value => {
          if (value) {
            return resolve(true);
          }
          console.error("MongoDB connection error:");
          return resolve(false);
        })
        .catch(err => {
          console.error("MongoDB connection error:", err);
          return resolve(false);
        });
    });
  }
  /**
   * @description: 创建数据库表 返回成功/失败
   * @return {*布尔型}
   */
  public static creatSchemas(): boolean {
    try {
      const tableList = monConf.tableList;
      for (let i = 0; i < tableList.length; i++) {
        const name = tableList[i];
        const struct = structList[name];
        if (struct) {
          const schema = new Schema(struct);
          for (const key in struct) {
            if (struct[key]["inc"]) {
              schema.plugin(mongooseSequence, { inc_field: key }); // 将 '字段' 设置为自增字段
            }
            if (struct[key]["unique"]) {
              schema.index({ [key]: 1 }, { unique: true });
            }
          }
          this._schemaList[name] = schema;
        }
      }
      return true;
    } catch (error) {
      console.log(error);
      return false;
    }
  }
  /**
   * @description: 插入创建一条数据 返回数据结构
   * @param {Istruct} doc 数据结构
   * @param {T} name 表名
   * @return {* Promise <数据结构>}
   */
  public static creatOneData<T extends Table>(name: Table, doc: NDefine.Obj): Promise<Istruct<T>> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        return Model.create(doc)
          .then(value => {
            return resolve(value as unknown as Istruct<T>);
          })
          .catch(err => {
            console.log("creatOneData", err);
            return resolve(null);
          });
      }
      return resolve(null);
    });
  }
  /**
   * @description: 创建多条数据 返回数据结构数组
   * @param {Istruct} doc 数据结构
   * @param {T} name 表名
   * @return {* Promise <数据结构>[]}
   */
  public static creatManyData<T extends Table>(doc: Istruct<T>[], name: Table): Promise<Istruct<T>[]> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        return Model.insertMany(doc)
          .then(value => {
            return resolve(value as unknown as Istruct<T>[]);
          })
          .catch(err => {
            console.log("creatManyData", err);
            return resolve(null);
          });
      }
      return resolve(null);
    });
  }
  /**
   * @description: 更新一条数据 返回成功/失败
   * @param {T} name 表名
   * @param {TCondition} conditions 更新条件
   * @param {Istruct} doc 数据结构
   * @param {Object} {option} 选项
   * @return {* Promise<布尔型>}
   */
  public static updateOneData(name: Table, conditions: NDefine.Obj, doc: NDefine.Obj, option: NDefine.Obj = { upsert: false }): Promise<boolean> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        option["runValidators"] = true;
        console.log(`Model.updateOne(${JSON.stringify(conditions)}, ${JSON.stringify(doc)}, ${JSON.stringify(option)})`);
        return Model.updateOne(conditions, doc, option)
          .then(value => {
            if (value?.acknowledged && (value?.matchedCount || value?.modifiedCount || value?.upsertedCount)) {
              return resolve(true);
            }
            return resolve(false);
          })
          .catch(err => {
            console.log("updateOneData", err);
            return resolve(null);
          });
      }
      return resolve(null);
    });
  }
  /**
   * @description: 更新多条数据 返回成功数量
   * @param {TCondition} conditions 更新条件
   * @param {Istruct} doc 数据结构
   * @param {T} name 表名
   * @return {* Promise<数值型>}
   */
  public static updateManyData(doc: NDefine.Obj, conditions: NDefine.Obj, name: Table): Promise<number> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        return Model.updateMany(conditions, doc, { multi: true })
          .then(value => {
            if (value?.acknowledged) {
              return resolve(value?.modifiedCount);
            }
            return resolve(0);
          })
          .catch(err => {
            console.log("updateManyData", err);
            return resolve(0);
          });
      }
      return resolve(0);
    });
  }
  /**
   * @description: 根据多条件更新多条数据 返回更新结果
   * @param {BulkOperations} bulkOperations 更新条件数组
   * @param {T} name 表名
   * @param {0} type 0 单文档1多文档
   * @param {boolean} insert 是否插入新
   * @return {*Promise<数值型>}
   */
  public static bulkWriteData<T extends Table = Table.user>(
    bulkOperations: BulkOperations<T>[],
    name: T = Table.user as any,
    type: 0 | 1 = 0,
    insert: boolean = false
  ): Promise<number> {
    return new Promise(resolve => {
      try {
        const schema = this._schemaList[name];
        if (schema) {
          const Model = mongoose.model(name, schema);
          const arry = [];
          for (let index = 0; index < bulkOperations.length; index++) {
            const item = bulkOperations[index];
            if (type == 0) {
              const obj = {
                updateOne: {
                  filter: item.condition,
                  update: { $set: item.doc },
                  upsert: insert
                }
              };
              arry.push(obj);
            } else if (type == 1) {
              const obj = {
                updateMany: {
                  filter: item.condition,
                  update: { $set: item.doc },
                  upsert: insert
                }
              };
              arry.push(obj);
            }
          }
          return Model.bulkWrite(arry)
            .then(value => {
              return resolve(value?.modifiedCount);
            })
            .catch(err => {
              console.log("bulkWriteData", err);
              return resolve(0);
            });
        }
        return resolve(0);
      } catch (error) {
        return resolve(null);
      }
    });
  }
  /**
   * @description: 查找一条数据更新返回数据结构
   * @param {T} name 表名
   * @param {TCondition} conditions 查找条件
   * @param {Istruct} doc 数据结构
   * @param {option} option 插入配置
   * @return {*Promise<数据结构>}
   */
  public static findOneAndUpdate<T extends Table>(
    name: Table,
    conditions: NDefine.Obj,
    doc: NDefine.Obj,
    option: NDefine.Obj = { upsert: false }
  ): Promise<Istruct<T>> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        option["runValidators"] = true;
        option["new"] = true;
        return Model.findOneAndUpdate(conditions, doc, option)
          .lean()
          .then(value => {
            if (value) {
              return resolve(value as unknown as Istruct<T>);
            }
            return resolve(null);
          })
          .catch(err => {
            console.log("findOneAndUpdate", err);
            return resolve(null);
          });
      }
      return resolve(null);
    });
  }
  /**
   * @description: 通过ID查找一条数据更新 返回结构数据
   * @param {T} name
   * @param {NDefine. Object} id
   * @param {Istruct} doc
   * @param {option} option
   * @return {*Promise<数据结构>}
   */
  public static findByIdAndUpdate<T extends Table>(
    name: Table,
    id: NDefine.Obj | Number | String,
    doc: NDefine.Obj,
    option: NDefine.Obj = { upsert: false }
  ): Promise<Istruct<T>> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        option["runValidators"] = true;
        return Model.findByIdAndUpdate(id, doc, option)
          .lean()
          .then(value => {
            if (value) {
              return resolve(value as unknown as Istruct<T>);
            }
            return resolve(null);
          })
          .catch(err => {
            console.log("findByIdAndUpdate", err);
            return resolve(null);
          });
      }
      return resolve(null);
    });
  }
  /**
   * @description:查找一条数据 返回数据结构
   * @param {T} name 表名
   * @param {TCondition} conditions 查找条件
   * @param {array} field 过滤字段['','']
   * @param {ISort} sort 是否排序（多个按最大或最小）
   * @return {*Promise<数据结构>}
   */
  public static findOneData<T extends Table>(
    name: Table,
    conditions: NDefine.Obj,
    field: string[] = [],
    sort: ISort<Istruct<T>> = null
  ): Promise<Istruct<T>> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        let fields: any = {};
        field.forEach(v => (fields[v] = 1));
        if (!fields["_id"]) {
          fields["_id"] = 0;
        }
        console.log(`Model.findOne(${JSON.stringify(conditions)},${JSON.stringify(fields)})`);
        return Model.findOne(conditions, fields, sort)
          .lean()
          .then(value => {
            if (value) {
              return resolve(value as unknown as Istruct<T>);
            }
            return resolve(null);
          })
          .catch(err => {
            console.log("findOneData", err);
            return resolve(null);
          });
      }
      return resolve(null);
    });
  }
  /**
   * @description: 根据ID查找一条数据 返回数据结构
   * @param {T} name 表名
   * @param {NDefine. Object} id id 字段
   * @param {array} field 过滤字段['','']
   * @return {*Promise<数据结构>}
   */
  public static findOneById<T extends Table>(name: Table, id: NDefine.Obj | Number | String, field: string[] = []): Promise<Istruct<T>> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        let fields: any = {};
        field.forEach(v => (fields[v as any] = 1));
        if (!fields["_id"]) {
          fields["_id"] = 0;
        }
        return Model.findById(id, fields)
          .lean()
          .then(value => {
            if (value) {
              return resolve(value as unknown as Istruct<T>);
            }
            return resolve(null);
          })
          .catch(err => {
            console.log("findOneById", err);
            return resolve(null);
          });
      }
      return resolve(null);
    });
  }
  /**
   * @description: 查找多条数据 返回数据结构数组
   * @param {T} name 表名
   * @param {TCondition} conditions 查找条件
   * @param {array} field 过滤字段['','']
   * @return {*Promise<数据结构>[]}
   */
  public static findManyData<T extends Table>(name: Table, conditions: NDefine.Obj, data?: NDefine.Obj): Promise<Istruct<T>[]> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        return Model.find(conditions, data)
          .lean()
          .then(value => {
            if (value) {
              return resolve(value as unknown as Istruct<T>[]);
            }
            return resolve(null);
          })
          .catch(err => {
            console.log("findManyData", err);
            return resolve(null);
          });
      }
      return resolve(null);
    });
  }
  /***/
  /**
   * @description: 删除一条数据 返回成功/失败
   * @param {T} name 表名
   * @param {TCondition} conditions 查找条件
   * @return {*Promise<布尔型>}
   */
  public static deleteOneData(name: Table, conditions: NDefine.Obj): Promise<boolean> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        return Model.deleteOne(conditions)
          .then(value => {
            if (value?.acknowledged) {
              return resolve(true);
            }
            return resolve(false);
          })
          .catch(err => {
            console.log("deleteOneData", err);
            return resolve(null);
          });
      }
      return resolve(null);
    });
  }
  /**
   * @description:删除多条数据 返回成功删除的数量
   * @param {T} name  表名
   * @param {TCondition} conditions 查找条件
   * @return {*Promise<数值型>}
   */
  public static deleteManyData(name: Table, conditions: NDefine.Obj): Promise<number> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        return Model.deleteMany(conditions)
          .then(value => {
            if (value?.acknowledged) {
              return resolve(value?.deletedCount);
            }
            return resolve(0);
          })
          .catch(err => {
            console.log("deleteOneData", err);
            return resolve(0);
          });
      }
      return resolve(0);
    });
  }
  /**
   * @description: 查询文档条目数量 返回文档数量
   * @param {T} name 表名
   * @param {TCondition} conditions 查询条件
   * @return {* Promise<数值型>}
   */
  public static countDocument(name: Table, conditions: NDefine.Obj): Promise<number> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        return Model.countDocuments(conditions)
          .then(value => {
            return resolve(value);
          })
          .catch(err => {
            console.log("deleteOneData", err);
            return resolve(0);
          });
      }
      return resolve(0);
    });
  }
  /**
   * @description: 删除一个集合框架 返回成功/失败
   * @param {Table} name 表名
   * @return {*Promise<布尔型>}
   */
  public static dropCollection(name: Table): Promise<boolean> {
    return new Promise(resolve => {
      const schema = this._schemaList[name];
      if (schema) {
        const Model = mongoose.model(name, schema);
        return Model.collection
          .drop()
          .then(value => {
            return resolve(value);
          })
          .catch(err => {
            console.log("dropCollection", err);
            return resolve(null);
          });
      }
      return resolve(null);
    });
  }
  /**
   * @description: 删除当前连接的整个数据库 返回成功/失败
   * @return {*Promise<布尔型>}
   */
  public static dropDatabase(): Promise<boolean> {
    return new Promise(resolve => {
      return mongoose.connection.db
        .dropDatabase()
        .then(() => {
          console.log("数据库已被删除");
          return resolve(true);
        })
        .catch(err => {
          console.error("删除数据库失败:", err);
          return resolve(false);
        });
    });
  }
}
